<?php

namespace App\Models;

use App\Activities\UserRepliedTopic;
use Carbon\Carbon;
use Naux\AutoCorrect;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laracasts\Presenter\PresentableTrait;
use Venturecraft\Revisionable\RevisionableTrait;
use Nicolaslopezj\Searchable\SearchableTrait;
use EstGroupe\Taggable\Taggable;

class Topic extends Model
{
    use Traits\TopicFilterable;
    use Traits\TopicApiHelper;
    use Traits\TopicImageHelper;
    use Taggable;

    // manually maintian
    public $timestamps = true;

    // For admin log
    use RevisionableTrait;
    protected $keepRevisionOf = [
        'deleted_at',
        'is_excellent',
        'is_blocked',
        'order',
    ];

    use SearchableTrait;
    protected $searchable = [
        'columns' => [
            'topics.title' => 10,
            'topics.body' => 5,
        ]
    ];

    use PresentableTrait;
    protected $presenter = 'Phphub\Presenters\TopicPresenter';

    use SoftDeletes;
    protected $dates = ['deleted_at'];

    //translate_status
    CONST NOT_NEED_TRANSLATE = 0; //default
    CONST NOT_TRANSLATED = 1;
    CONST IS_TRANSLATED = 2;

    // Don't forget to fill this array
    protected $fillable = [
        'title',
        'slug',
        'body',
        'excerpt',
        'is_draft',
        'source',
        'body_original',
        'user_id',
        'category_id',
        'created_at',
        'updated_at',
        'translate_status',
        'original_url',
        'translation_url',
    ];

    public static function boot()
    {
        parent::boot();

        static::created(function ($topic) {
            SiteStatus::newTopic();
        });

        static::deleted(function ($topic) {
            foreach ($topic->replies as $reply) {
                app(UserRepliedTopic::class)->remove($reply->user, $reply);
            }
        });
    }

    public function share_link()
    {
        return $this->hasOne(ShareLink::class);
    }

    public function votes()
    {
        return $this->morphMany(Vote::class, 'votable');
    }

    public function attentedUsers()
    {
        return $this->belongsToMany(User::class, 'attentions')->get();
    }

    public function votedUsers()
    {
        $user_ids = Vote::where('votable_type', Topic::class)
            ->where('votable_id', $this->id)
            ->where('is', 'upvote')
            ->lists('user_id')
            ->toArray();
        return User::whereIn('id', $user_ids)->get();
    }

    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function resource()
    {
        return $this->hasOne(Resource::class);
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function lastReplyUser()
    {
        return $this->belongsTo(User::class, 'last_reply_user_id');
    }

    public function replies()
    {
        return $this->hasMany(Reply::class);
    }

    public function blogs()
    {
        return $this->belongsToMany(Blog::class, 'blog_topics');
    }

    public function appends()
    {
        return $this->hasMany(Append::class);
    }

    public function generateLastReplyUserInfo()
    {
        $lastReply = $this->replies()->recent()->first();

        $this->last_reply_user_id = $lastReply ? $lastReply->user_id : 0;
        $this->save();
    }

    public function getRepliesWithLimit($limit = 30, $order = 'created_at', $read_right = 0)
    {
        $pageName = 'page';
        // Default display the latest reply
        $latest_page = is_null(\Input::get($pageName)) ? ceil($this->reply_count / $limit) : 1;
        if ($read_right == 1) {
            return Reply::where('topic_id', 0)->paginate($limit, ['*'], $pageName, $latest_page);
        }
        $query = $this->replies()->with('user');

        $query = ($order == 'vote_count')
            ? $query->orderBy('vote_count', 'desc')
            : $query->orderBy('created_at', 'asc');



        return $query->paginate($limit, ['*'], $pageName, $latest_page);
    }

    public function getSameCategoryTopics()
    {
        $data = Cache::remember('phphub_hot_topics_' . $this->category_id, 30, function () {
            return Topic::where('category_id', '=', $this->category_id)
                ->recent()
                ->with('user')
                ->take(3)
                ->get();
        });
        return $data;
    }

    public function getArticleArchieve($user_id)
    {
        $archieve_list = ArticleArchieve::where('user_id', $user_id)
            ->orderBy('archieved_at', 'DESC')
            ->get();

        $cur_archieve = $this->curMonthArticleArchieve($user_id);
        if ($cur_archieve) {
            $archieve_list->prepend($cur_archieve);
        }

        return $archieve_list;
    }

    protected function curMonthArticleArchieve($user_id)
    {
        $date = date_format(Carbon::now(), 'Y-m');
        $start_time = date_format(Carbon::now(), 'Y-m') . '-00 00:00:00';
        $end_time = date_format(Carbon::now()->addMonth(), 'Y-m') . '-00 00:00:00';

        $article_list = Topic::select('id', 'user_id', 'created_at')->where('created_at', '>=', $start_time)
            ->where('created_at', '<', $end_time)
            ->byWhom($user_id)
            ->withoutDraft()
            ->onlyArticle()
            ->get();
        $data = null;
        if ($article_list && count($article_list)) {
            $data = new ArticleArchieve();
            $data->user_id = $user_id;
            $data->archieved_at = $date;
            foreach ($article_list as $key => $article) {
                $data->article_count += 1;
                $data->article_ids = $data->article_ids ? $data->article_ids . '-' . $article->id : $article->id;

            }
        }
        return $data;

    }

    public static function makeExcerpt($body)
    {
        $html = $body;
        $excerpt = trim(preg_replace('/\s\s+/', ' ', strip_tags($html)));
        return str_limit($excerpt, 200);
    }

    public function setTitleAttribute($value)
    {
        $this->attributes['title'] = (new AutoCorrect)->convert($value);
    }

    public function scopeByWhom($query, $user_id)
    {
        return $query->where('user_id', '=', $user_id);
    }

    public function scopeDraft($query)
    {
        return $query->where('is_draft', '=', 'yes');
    }

    public function scopeWithoutDraft($query)
    {
        return $query->where('is_draft', '=', 'no');
    }

    public function scopeRecent($query)
    {
        return $query->orderBy('created_at', 'desc');
    }

    public function getRandomExcellent()
    {
        $data = Cache::remember('phphub_random_topics', 10, function () {
            $topic = new Topic;
            return $topic->getTopicsWithFilter('random-excellent', 5);
        });
        return $data;
    }

    public function isArticle()
    {
        return $this->category_id == config('phphub.blog_category_id');
    }

    public function isShareLink()
    {
        return $this->category_id == config('phphub.hunt_category_id');
    }

    public function isHomeWork()
    {
        return $this->category_id == config('phphub.homework_help_id');
    }

    public function isResources()
    {
        return $this->category_id == config('phphub.resources_id');
    }

    public function isTranslate()
    {
        return $this->category_id == config('phphub.translate_id');
    }

    public function isTranslated()
    {
        return $this->translate_status == self::IS_TRANSLATED;
    }

    public function link($params = [])
    {
        $params = array_merge([$this->id, $this->slug], $params);
        $name = $this->isArticle() ? 'articles.show' : 'topics.show';
        return str_replace(env('API_DOMAIN'), env('APP_DOMAIN'), route($name, $params));
    }

    public function translateSections()
    {
        return $this->hasMany(TranslateSection::class, 'topic_id', 'id');
    }

    public function translatorCount()
    {
        $user_cnt = 0;
        foreach ($this->translateSections AS $section)
        {
            $user_cnt += $section->translator_count;
        }
        return $user_cnt;
    }

    public function translators()
    {
        $user_list = new Collection();
        foreach ($this->translateSections AS $section)
        {
            $users = $section->translators();
            foreach ($users AS $user)
            {
                if($user && !$user_list->contains($user))
                {
                    $user_list = $user_list->push($user);
                }
            }

        }

        return $user_list;
    }

    public function translatorIds()
    {
        $user_ids = [];
        foreach ($this->translateSections AS $section)
        {
            $user_ids = array_merge($user_ids, $section->translatorIds());
        }
        $user_ids = array_unique($user_ids);
        return $user_ids;
    }

    public function improvedUserIds()
    {
        $user_ids = [];
        foreach ($this->translateSections AS $section)
        {
            $user_ids = array_merge($user_ids, $section->improvedUserIds());
        }
        return array_unique($user_ids);
    }

    public function transInfo()
    {
        $trans_info['user_cnt'] = 0;
        $trans_info['un_section_cnt'] = 0;
        $trans_info['total_section_cnt'] = count($this->translateSections);
        foreach ($this->translateSections AS $section)
        {
            $trans_info['user_cnt'] += $section->translator_count;
            if($section->is_translated == TranslateSection::NOT_TRANSLATED)
            {
                $trans_info['un_section_cnt']++;
            }
        }
        if($trans_info['total_section_cnt'])
        {
            $trans_info['trans_progress_int'] = floor(100 * ($trans_info['total_section_cnt'] - $trans_info['un_section_cnt']) / $trans_info['total_section_cnt']);
        }
        else
        {
            $trans_info['trans_progress_int'] = 0;
        }

        return $trans_info;
    }

    public static function translate_draft_count()
    {
        return self::where(['category_id' => config('phphub.translate_id'),'is_draft' => 'yes'])
            ->count();
    }

}
